package message;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactoryConfigurationError;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import comunity.Community;
import comunity.GPSLocation;
import comunity.Status;
import comunity.User;

public class CommunityStatusNotificaton extends Packet {

	private String receiver;

	private static final String USER_TAG = "user";
	private static final String RECEIVER_ATTRIBUTE = "receiver";
	private static final String USERNAME_ATTRIBUTE = "username";
	private static final String STATUS_ATTRIBUTE = "status";

	public CommunityStatusNotificaton(String receiver, int port) {
		super(PacketType.COMMUNITY_STATUS_NOTIFICATION, port, -1, -1);
		this.receiver = receiver;
	}

	@Override
	public String toXML() {
		Document doc = null;
		try {
			doc = super.createXMLDocument();
		} catch (ParserConfigurationException e1) {
			e1.printStackTrace();
		}

		Element root = doc.createElement(rootElementTag());
		root.setAttribute(RECEIVER_ATTRIBUTE, receiver);
		doc.appendChild(root);

		Element connectionElement = super.createConnectionElement(doc);
		root.appendChild(connectionElement);

		Community community = Community.obtainCommunity();
		Collection<String> usernames = community.getUsers();
		for (String username : usernames) {
			Status status = community.getUserStatus(username);
			GPSLocation gpsLocation = community.getUserGPSLocation(username);

			double lat = gpsLocation.getLat(), lon = gpsLocation.getLon();
			
			Element userElement = this.createUserElement(doc, username, status, lat, lon);
			root.appendChild(userElement);
		}

		String result = null;
		try {
			result = super.generateString(doc);
		} catch (TransformerFactoryConfigurationError | TransformerException e) {
			e.printStackTrace();
		}
		return result;
	}

	public static CommunityStatusNotificaton createCommunityStatusNotificaton(
			String xmlString) {
		Document doc = Packet.createXMLDocumentFromString(xmlString);

		NodeList list = doc
				.getElementsByTagName(PacketType.COMMUNITY_STATUS_NOTIFICATION
						.toString());
		Node rootNode = list.item(0);
		NamedNodeMap rootAttributes = rootNode.getAttributes();

		NodeList childList = rootNode.getChildNodes();
		List<User> users = new LinkedList<>();

		Node connectionNode = childList.item(0);
		NamedNodeMap connectionAttribute = connectionNode.getAttributes();

		for (int i = 1; i < childList.getLength(); i++) {
			Node userNode = childList.item(i);
			NamedNodeMap userAttribute = userNode.getAttributes();
			users.add(new User(userAttribute.getNamedItem(STATUS_ATTRIBUTE).getNodeValue(),
					userAttribute.getNamedItem(USERNAME_ATTRIBUTE).getNodeValue(),
					Double.parseDouble(userAttribute.getNamedItem(Packet.LAT_ATTRIBUTE).getNodeValue()),
					Double.parseDouble(userAttribute.getNamedItem(Packet.LON_ATTRIBUTE).getNodeValue())));
		}

		return new CommunityStatusNotificaton(rootAttributes.getNamedItem(
				RECEIVER_ATTRIBUTE).getNodeValue(), Integer.parseInt(connectionAttribute.getNamedItem(
						Packet.PORT_ATTRIBUTE).getNodeValue()));
	}

	private Element createUserElement(Document doc, String username, Status status, double lat, double lon) {
		Element userElement = doc.createElement(CommunityStatusNotificaton.USER_TAG);
		userElement.setAttribute(CommunityStatusNotificaton.USERNAME_ATTRIBUTE, username);
		userElement.setAttribute(CommunityStatusNotificaton.STATUS_ATTRIBUTE, status.toString());
		userElement.setAttribute(Packet.LAT_ATTRIBUTE, Double.toString(lat));
		userElement.setAttribute(Packet.LON_ATTRIBUTE, Double.toString(lon));		

		return userElement;
	}

	@Override
	String rootElementTag() {
		return PacketType.COMMUNITY_STATUS_NOTIFICATION.toString();
	}

	public String getReceiver() {
		return receiver;
	}
}
